﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ESpace;
using System.IO;
using ElementClasses;

namespace Organizer
{
    public partial class FormMain : Form
    {
        /* bool isEditItem_ = false;
         /// <summary> редактируется какой-то элемент. При редактировании не отправляются запросы на синхронизацию, а если пришел ответ (любой) он ожидает</summary>
         public bool IsEditItem
         {
             get { return isEditItem_; }
             set
             {
                 isEditItem_ = value;
                 if (isEditItem_)
                 {
                     EnableNextManualReqest = false;
                 }
                 else
                 {
                     EnableNextManualReqest = true;
                 }
             }
         }

         // Следующая отправка разрешена
         public bool EnableNextManualReqest
         {
             get { return mBtnEditService.Enabled; }
             set
             {
                 mBtnEditService.Enabled = value;
                 //mBtnUpdateNet.Enabled = value;
             }
         }*/

        // текущие каталоги
        DIR dir1_;
        DIR Dir1
        {
            get { return dir1_; }
            set
            {
                dir1_ = value;
                DIR sysDir = Gl.GetParentSystemDir(dir1_);
                if (sysDir.FullPath == LocalDir.FullPath) LastLocalDir = dir1_.FullPath;
                if (sysDir.FullPath == NetDir.FullPath) LastNetDir = dir1_.FullPath;
            }
        }
        DIR dir2_;
        DIR Dir2
        {
            get { return dir2_; }
            set
            {
                dir2_ = value;
                DIR sysDir = Gl.GetParentSystemDir(dir2_);
                if (sysDir.FullPath == LocalDir.FullPath) LastLocalDir = dir2_.FullPath;
                if (sysDir.FullPath == NetDir.FullPath) LastNetDir = dir2_.FullPath;
            }
        }

        DIR LocalDir;
        DIR NetDir;
        DIR RecyclerDir;

        // последние выбранные каталоги для дисков
        String LastLocalDir;
        String LastNetDir;

        FormService frmServ;

        DateTime dtNextGetVertion = DateTime.MinValue; // время следующего планового запроса на синхронизацию
        DateTime dtReconnet = DateTime.MinValue;

        #region *** События формы **************************************************************************

        public FormMain()
        {
            InitializeComponent();
            lblStat.Text = "";
            splitContainer1.Panel1MinSize = 300;
            splitContainer1.Panel2MinSize = 300;

            Gl.ExtFunc = new API_Funtions(Gl.DeleteItem, RefillListsIfNeed, Gl.AddElInDeleteNetList, UpdateIcoInDirIfNeed, Gl.SaveDB, Gl.SaveSettings, RefillComments);

            // создание модулей
            Gl.LoadUnins(imL);

            Gl.dPathHistory = Application.StartupPath + "\\History"; // (создание каталога идет по мере необходимости)
            Gl.dPathDebug = Application.StartupPath + "\\Debug"; // (создание каталога идет по мере необходимости)
            Gl.dPathExternalExe = Application.StartupPath + "\\ExExe"; if (!Directory.Exists(Gl.dPathExternalExe)) Directory.CreateDirectory(Gl.dPathExternalExe);
            Gl.dPathExternalNetUnits = Application.StartupPath + "\\ExNetUnits"; if (!Directory.Exists(Gl.dPathExternalNetUnits)) Directory.CreateDirectory(Gl.dPathExternalNetUnits);
            Gl.dPathExternalNetLocalData = Gl.dPathExternalNetUnits + "\\LocalData"; if (!Directory.Exists(Gl.dPathExternalNetLocalData)) Directory.CreateDirectory(Gl.dPathExternalNetLocalData);
            Gl.dPathExternalNetHistory = Gl.dPathExternalNetUnits + "\\History"; if (!Directory.Exists(Gl.dPathExternalNetHistory)) Directory.CreateDirectory(Gl.dPathExternalNetHistory);

            // загрузка настроек
            Gl.fPathSett = Application.StartupPath + "\\Settings.stngs";
            Gl.sett = new Settings();
            frmServ = new FormService(this);
            mBtnGuests.Checked = Gl.sett.Guests;

            LoadUserLocalData();
            foreach (ExtElementUnit ext in Gl.exl) ext.ExElm.EndCreate();

            #region *** меню для видимых элементов **********************
            ToolStripMenuItem tBtn;
            // добавить
            foreach (KeyValuePair<string, IElementUnit> u in Gl.unL)
            {
                if (!u.Value.IsVisibleUnit) continue;
                VisibleUnit vU = (VisibleUnit)u.Value;

                tBtn = new ToolStripMenuItem("Добавить " + vU.MenuName);
                tBtn.Click += new EventHandler(mBtnAdd_Click);
                tBtn.Name = "mBtnAdd1_" + u.Key;
                tBtn.Tag = 1;
                menu1.Items.Add(tBtn);

                tBtn = new ToolStripMenuItem("Добавить " + vU.MenuName);
                tBtn.Click += new EventHandler(mBtnAdd_Click);
                tBtn.Name = "mBtnAdd2_" + u.Key;
                tBtn.Tag = 2;
                menu2.Items.Add(tBtn);
            }
            menu1.Items.Add(new ToolStripSeparator());
            menu2.Items.Add(new ToolStripSeparator());
            // удалить
            tBtn = new ToolStripMenuItem("Удалить");
            tBtn.Click += new EventHandler(mBtnDel_Click);
            tBtn.Name = "mBtnDel1";
            tBtn.Tag = 1;
            menu1.Items.Add(tBtn);
            tBtn = new ToolStripMenuItem("Удалить");
            tBtn.Click += new EventHandler(mBtnDel_Click);
            tBtn.Name = "mBtnDel2";
            tBtn.Tag = 2;
            menu2.Items.Add(tBtn);
            #endregion *** меню **********************

            #region *** добавление элементов меню для скрытых модулей и внелементов **************

            int AddInd = 0; // счетчик добавленых элементов для вставки

            // добавление элементов меню для скрытых модулей
            foreach (KeyValuePair<string, IElementUnit> u in Gl.unL)
            {
                if (!u.Value.IsVisibleUnit)
                {
                    HiderUnit hUnt = (HiderUnit)u.Value;
                    if (hUnt.NotifyMenuBotton != null)
                    {
                        menuTray.Items.Insert(AddInd, hUnt.NotifyMenuBotton);
                        AddInd++;
                    }
                }
            }

            // добавление элементов меню для внелементов
            foreach (ExtElementUnit ext in Gl.exl)
            {
                if (ext.ExElm.NotifyMenuBotton != null)
                {
                    menuTray.Items.Insert(AddInd, ext.ExElm.NotifyMenuBotton);
                    AddInd++;
                }
            }

            if (AddInd > 0)
            {
                menuTray.Items.Insert(AddInd, new ToolStripSeparator());
                AddInd++;
            }

            #endregion *** добавление элементов меню для скрытых модулей и внелементов **************

            #region *** ВНЕШНИЕ МОДУЛИ *****************************************

            // загрузка информации по внешним модулям
            Gl.LoadExternalEXE(menuTray);

            #region *** добавление элементов меню внешних модулей **************

            int AddIndExe = 0; // счетчик добавленых элементов для вставки

            ToolStripMenuItem itm = new ToolStripMenuItem("Внешние модули");
            foreach (ExternalExe exExe in Gl.exExeL)
            {
                if (exExe.MenuItm != null)
                {
                    itm.DropDownItems.Add(exExe.MenuItm);
                    AddIndExe++;
                }
            }

            if (AddIndExe > 0)
            {
                menuTray.Items.Insert(AddInd, itm); AddInd++;
                menuTray.Items.Insert(AddInd, new ToolStripSeparator()); AddInd++;
            }

            #endregion *** добавление элементов меню для внешних модулей **************

            // старт модулей при старте органайзера
            foreach (ExternalExe exExe in Gl.exExeL)
            {
                if ((exExe.StartEvents & ExExeStartEventFlags.StartOrganizer) != ExExeStartEventFlags.None) exExe.Start();
                if ((exExe.StartEvents & ExExeStartEventFlags.GuestMode) != ExExeStartEventFlags.None && Gl.sett.Guests) exExe.Start();
                if ((exExe.StartEvents & ExExeStartEventFlags.NotGuestMode) != ExExeStartEventFlags.None && !Gl.sett.Guests) exExe.Start();
            }

            #endregion *** ВНЕШНИЕ МОДУЛИ *****************************************

            tBtnRecycler1.Image = RecyclerDir.Items.Count == 0 ? Properties.Resources.recycle_empty : Properties.Resources.recycle_full;
            btnClearRecycler.Enabled = RecyclerDir.Items.Count > 0;

            // выполнение начальных действий в скрытых юнитах
            foreach (KeyValuePair<string, IElementUnit> u in Gl.unL) u.Value.EndCreate();

            tBtnDebugFunc.Visible = Gl.sett.DEBUG_MODE;

            // ширины столбцов (иначе они согранятся по умоланию)
            clmName1.Width = Gl.sett.ClmWidth1_Name;
            clmName2.Width = Gl.sett.ClmWidth2_Name;
            clmComm1.Width = Gl.sett.ClmWidth1_Comm;
            clmComm2.Width = Gl.sett.ClmWidth2_Comm;

            if (!Gl.sett.DEBUG_MODE)
            {
                lv1.Columns.RemoveAt(2);
                lv2.Columns.RemoveAt(2);
            }

        }

        private void FormMain_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized && Visible) Hide();
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing && !bClose)
            {
                if (WindowState != FormWindowState.Minimized) WindowState = FormWindowState.Minimized;
                e.Cancel = true;
            }
        }

        private void FormMain_Shown(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized) Hide();

            lv_ClientSizeChanged(lv1, null);
            lv_ClientSizeChanged(lv2, null);

            // временно для отладки сразу показываем форму ежедневника
            /* menuTray.Items[1].PerformClick();
             bClose = true;
             Close();*/

            SetAllDateNextGetVertion(DateTime.Now);
            tmrMain.Start();
        }

        private void FormMain_ResizeEnd(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                Gl.sett.Frm_Size = Size;
                Gl.sett.Save();
            }
        }

        DateTime dtReSaveSett = DateTime.MaxValue;
        private void FormMain_Move(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Normal && !bWriteLocation)
            {
                Gl.sett.Frm_Location = Location;
                dtReSaveSett = DateTime.Now.AddSeconds(2);
            }
        }

        #endregion *** События формы **************************************************************************

        void LoadUserLocalData()
        {
            string dPathLocalData = Application.StartupPath + "\\LocalData";
            if (!Directory.Exists(dPathLocalData)) Directory.CreateDirectory(dPathLocalData);
            Gl.fPathDB = dPathLocalData + "\\LocalData_" + Comm.GetValidFileName(Gl.sett.Login) + ".db";
            Gl.DelList = new DeleteNetCollection(dPathLocalData + "\\DelList_" + Comm.GetValidFileName(Gl.sett.Login) + ".dList");

            // загрузка базы
            ESpace.DBItem.LoadRec = new ESpace.LoadRecDelegate(Gl.LoadRec);
            Gl.LoadDB();

            Gl.LoadUninsExElm();

            LocalDir = Gl.GetSystemDir(Gl.SystemDir.Local);
            NetDir = Gl.GetSystemDir(Gl.SystemDir.Net);
            RecyclerDir = Gl.GetSystemDir(Gl.SystemDir.Recycler);

            // сбрасываем статусы Write при загрузке. Они могут быть сохранены, если был запрос, было сохранение во время запроса и приложение закрылось до приема ответа
            Gl.ResetWriteStatus(false);
            Gl.ResetWriteStatusAllExEl();

            Dir1 = LocalDir;
            Dir2 = NetDir;

            RefillList(1);
            RefillList(2);

        }

        #region *** Синхронизация **************************************************************************

        private void tmrMain_Tick(object sender, EventArgs e)
        {
            tmrMain.Stop();

            try
            {

                if (Gl.sett.DEBUG_MODE) Text = "Версия базы: " + Gl.ServVertion.ToString();

                if (DateTime.Now >= dtReSaveSett)
                {
                    Gl.sett.Save();
                    dtReSaveSett = DateTime.MaxValue;
                }

                DateTime tmrDt = DateTime.Now;

                // тики модулей
                foreach (KeyValuePair<string, IElementUnit> u in Gl.unL) u.Value.TimerTick(tmrDt, Gl.DB);
                //foreach (ExtElementUnit ext in Gl.exl) ext.ExElm.TimerTick(tmrDt);
                // тики элементов
                List<DBItem> el = Gl.GetAllItems(Gl.DB);
                foreach (DBItem elm in el) ((Element)elm).TimerTick(tmrDt, Gl.DB);

                // сохранение внелементов
                foreach (ExtElementUnit ExU in Gl.exl)
                {
                    if (ExU.ExElm.IsSaveData)
                    {
                        Gl.AddDebugLogTitle("Сохранение внелемента '" + ExU.ExElm.Name + "'");
                        ExU.NetStat = eeNetStatus.NotActual;
                        ExU.SaveData();
                        ExU.ExElm.IsSaveData = false;
                    }
                }

                #region *** сетевые коммуникации ******************************************

                // проверка, нет ли редактирования какого-либо внутреннего сетевого элемента
                bool bEditInElm = false;
                el = Gl.GetAllItems(NetDir);
                foreach (DBItem elm in el)
                {
                    if (((Element)elm).IsEdit) { bEditInElm = true; break; }
                }

                // установка статуса
                if (bEditInElm) lblStat.Text = "Идет редактирование сетевого элемента";
                else if (Gl.ConnState == Gl.ConnectState.OffLine) lblStat.Text = "Нет связи с сервером";
                else if (Gl.ConnState == Gl.ConnectState.Sync) lblStat.Text = "Идут коммуникации с бд";
                else lblStat.Text = "";

                // если ожидается обновление каталогов после синхронизации и ничего не редактируется в данный момент
                if (Gl.SyncData != null && !bEditInElm)
                {
                    Gl.ResetWriteStatus(false);
                    Gl.Sinhronize(Gl.SyncData.Dir);
                    Gl.ServVertion = Gl.SyncData.ServVertion;
                    Gl.IsActualFlag = true;
                    EndSinhronize(Gl.SinhronizeResult.NEW_VERTION);
                    Gl.SaveDB();

                    Gl.SyncData = null;
                }

                // проверка ожидания синхронизации для внелементов
                foreach (ExtElementUnit ExU in Gl.exl)
                {
                    if (ExU.SyncSourceData != null && !ExU.ExElm.IsEdit)
                    {
                        Gl.SinhronizeExElm(ExU);
                        ExU.SaveData();
                    }
                }

                // если нет запросов (OK или ошибка) и нет задержки до следующего реконнекта
                if (dtReconnet < tmrDt && (Gl.ConnState == Gl.ConnectState.OnLine || Gl.ConnState == Gl.ConnectState.OffLine))
                {
                    // если ожидаются данные для синхронизации (то есть на сервере версия уже явно новее) смысла делать запросы для внутренних элементов нет
                    if (Gl.SyncData == null)
                    {
                        // если есть изменения, отправляем на запись
                        if (NeedWrite())
                        {
                            Gl.AddDebugLogTitle("ЗАПРОС НА ЗАПИСЬ");
                            frmServ.RequestSinc(NetDir, false);
                            UpdateIcoIfNeed();
                            dtNextGetVertion = tmrDt.AddSeconds(300);
                        }
                        // запросить серверную версию
                        else if (dtNextGetVertion <= tmrDt)
                        {
                            Gl.AddDebugLogTitle("ЗАПРОС НА ПЛАНОВУЮ СИНХРОНИЗАЦИЮ");
                            frmServ.RequestSinc(NetDir, false);
                            UpdateIcoIfNeed();
                            dtNextGetVertion = tmrDt.AddSeconds(300);

                        }
                    }

                    // проверка внелементов на необходимость синхронизации
                    foreach (ExtElementUnit ExU in Gl.exl)
                    {
                        if(ExU.SyncSourceData == null)
                        {
                            if (ExU.NetStat == eeNetStatus.NotActual)
                            {
                                Gl.AddDebugLogTitle("ЗАПРОС НА СИНХРОНИЗАЦИЮ ДЛЯ ВНЕЛЕМЕНТА '" + ExU.ExElm.Name + "'");
                                ExU.NetStat = eeNetStatus.Write;
                                frmServ.RequestSincExElm(false, ExU, new FormService.ResultDelegate(ExElmCommFunction_Result));
                                ExU.dtNextGetVertion = tmrDt.AddSeconds(300);
                            }
                            // запросить серверную версию
                            else if (ExU.dtNextGetVertion <= tmrDt)
                            {
                                Gl.AddDebugLogTitle("ЗАПРОС НА ПЛАНОВУЮ СИНХРОНИЗАЦИЮ ДЛЯ ВНЕЛЕМЕНТА '" + ExU.ExElm.Name + "'");
                                frmServ.RequestSincExElm(true, ExU, new FormService.ResultDelegate(ExElmCommFunction_Result));
                                ExU.dtNextGetVertion = tmrDt.AddSeconds(300);
                            }
                        }
                    }

                }

                #endregion *** сетевые коммуникации ******************************************

            }
            catch (Exception ex)
            {
                Gl.AddDebugLog("ОШИБКА ТАЙМЕРА!", "ОШИБКА: " + ex.Message + "\r\nТРИССИРОВКА: " + ex.StackTrace, true);
                if (MessageBox.Show("Произошла ошибка. Продолжить работу?\r\n\r\nОШИБКА:\r\n " + ex.Message + "\r\n ТРИССИРОВКА:\r\n" + ex.StackTrace, "Ошибка органайзера", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == System.Windows.Forms.DialogResult.No)
                {
                    bClose = true;
                    Close();
                }
            }
            tmrMain.Start();

        }

        /// <summary>Завершение коммуникаций для внутренних элементов</summary>
        public void EndSinhronize(Gl.SinhronizeResult result)
        {
            if (result == Gl.SinhronizeResult.NEW_VERTION)
            {
                // если каталог1 сетевой, обновляем список
                if (Gl.GetParentSystemDir(Dir1).FullPath == NetDir.FullPath)
                {
                    if (DBItem.GetItemByPath(Dir1.FullPath, Gl.DB) == null) Dir1 = NetDir;
                    RefillList(lv1, Dir1);
                }
                // если каталог2 сетевой, обновляем список
                if (Gl.GetParentSystemDir(Dir2).FullPath == NetDir.FullPath)
                {
                    if (DBItem.GetItemByPath(Dir2.FullPath, Gl.DB) == null) Dir2 = NetDir;
                    RefillList(lv2, Dir2);
                }
            }

            // если ошибка коммуникаций, делать попытки каждые 15 сек
            if (result == Gl.SinhronizeResult.ERROR)
            {
                dtReconnet = DateTime.Now.AddSeconds(15);
                dtNextGetVertion = DateTime.Now.AddSeconds(15);
            }

            // обновляем иконки, если сть необходимость
            UpdateIcoIfNeed();

            // вызываем EndSinhronize у всех скрытых юнитов
            foreach (KeyValuePair<string, IElementUnit> u in Gl.unL)
                if (!u.Value.IsVisibleUnit) { ((HiderUnit)u.Value).EndSinhronize(result); }

            //EnableNextManualReqest = true;
            RefillComments();

        }

        /// <summary>Завершение коммуникаций для внелементов</summary>
        public void ExElmCommFunction_Result(object CommFunctionData, object ResultData, bool ActionIsOK)
        {
            ServExtElementData rData = (ServExtElementData)ResultData;
            FormService.ExElmCommFunctionData cData = (FormService.ExElmCommFunctionData)CommFunctionData;

            ExtElementUnit ExU = cData.ExU;
            if (!ActionIsOK)
            {
                if (ExU.NetStat == eeNetStatus.Write)
                {
                    ExU.NetStat = eeNetStatus.NotActual;
                    ExU.SaveData();
                }
                dtReconnet = DateTime.Now.AddSeconds(15);
                ExU.dtNextGetVertion = DateTime.Now.AddSeconds(15);
            }
            else
            {
                switch (rData.stat)
                {
                    case ExElmResultStat.NewVertion:
                        {
                            // возводим ожидание синхронизации
                            ExU.SyncServVer = rData.ServVer;
                            ExU.SyncSourceData = rData.SourceData;

                            Gl.AddDebugLog("SQL -> для Внелемента '" + ExU.ExElm.Name + "' Пришел ответ: Требуется синхронизация. Версия сервера=" + rData.ServVer.ToString() + " локальная=" + ExU.ServVertion.ToString(), false);
                            break;
                        }
                    case ExElmResultStat.VertionOK:
                        {
                            Gl.IsActualFlag = true;
                            Gl.AddDebugLog("SQL -> для Внелемента '" + ExU.ExElm.Name + "' Пришел ответ: Версия Актуальна", false);
                            break;
                        }
                    case ExElmResultStat.WriteOK:
                        {
                            ExU.ServVertion = rData.ServVer;
                            ExU.NetStat = eeNetStatus.Actual;
                            ExU.SaveData();

                            Gl.AddDebugLog("SQL -> для Внелемента '" + ExU.ExElm.Name + "' Пришел ответ: Запись успешна. Новая версия=" + ExU.ServVertion.ToString(), false);
                            break;
                        }
                }
            }

        }

        // публичные данные нуждаются в записи на сервер
        bool NeedWrite()
        {
            if (Gl.DelList.Count > 0) return true;
            // если сейчас редактируется стикер, писать нельзя
            //if (dtNextSaveSticker != DateTime.MinValue) return false;

            List<DBItem> el = Gl.GetAllItems(NetDir);
            for (int i = 0; i < el.Count; i++)
                if (((Element)el[i]).NetStat == NetStatus.NotActual) return true;

            return false;
        }

        #endregion *** Синхронизация **************************************************************************

        #region *** Прочие Фии *********************************************************************************

        #region *** Refill *******************************************************

        // перерисовка листов
        void RefillList(int ListNum)
        {
            if (ListNum == 1) RefillList(lv1, Dir1);
            else RefillList(lv2, Dir2);
        }

        // перерисовка листов
        void RefillList(ListView lv, DIR Dir)
        {
            Label lblPath = lv == lv1 ? lblPath1 : lblPath2;

            lv.Items.Clear();
            if (!Dir.IsSystemDir) lv.Items.Add("[..]", 0);
            Dir.Items.Sort();
            for (int i = 0; i < Dir.Items.Count; i++)
            {
                Element elm = ((Element)Dir.Items[i]);
                if (Gl.sett.DEBUG_MODE || !elm.IsHider)
                {
                    ListViewItem itm = new ListViewItem(new string[3] { elm.IsHider ? elm.NameExt : elm.Name, elm.GetComment(), elm.ServVertion.ToString() }, Gl.GetIcoInd(elm));
                    itm.Tag = elm;
                    lv.Items.Add(itm);
                }
            }

            lblPath.Text = GetPath(Dir) + "\\*.*";

        }

        void RefillComments(Element Dir)
        {
            if (Dir.FullPath == Dir1.FullPath) RefillComments(lv1, Dir1);
            if (Dir.FullPath == Dir2.FullPath) RefillComments(lv2, Dir2);
        }

        void RefillComments()
        {
            RefillComments(lv1, Dir1);
            RefillComments(lv2, Dir2);
        }

        void RefillComments(ListView lv, DIR Dir)
        {
            int cnt = 0;
            if (!Dir.IsSystemDir) cnt++;
            for (int i = 0; i < Dir.Items.Count; i++)
            {
                Element elm = ((Element)Dir.Items[i]);
                if (Gl.sett.DEBUG_MODE || !elm.IsHider)
                {
                    lv.Items[cnt].SubItems[1].Text = elm.GetComment();
                    lv.Items[cnt].SubItems[2].Text = elm.ServVertion.ToString();
                    cnt++;
                }
            }
        }

        // перерисовка листов, если необходимо. Если открыт каталог, который необходимо обновить
        void RefillListsIfNeed(Element refillDir)
        {
            if (Dir1.FullPath == refillDir.FullPath) RefillList(1);
            if (Dir2.FullPath == refillDir.FullPath) RefillList(2);
        }

        // проверка второго листа при изменении первого
        void RefillOtherListIfNeed(int ListNum)
        {
            if (ListNum == 1) RefillOtherListIfNeed(lv1, Dir1, false);
            else RefillOtherListIfNeed(lv2, Dir2, false);
        }

        void RefillOtherListIfNeed(ListView lvEdit, DIR DirEdit)
        {
            RefillOtherListIfNeed(lvEdit, DirEdit, false);
        }

        void RefillOtherListIfNeed(ListView lvEdit, DIR DirEdit, bool RefillIfOneSyssDir)
        {
            // смотрим друго лист
            ListView lvOther = lvEdit == lv1 ? lv2 : lv1;
            DIR dirOthier = lvEdit == lv1 ? Dir2 : Dir1;
            DIR sysDir = Gl.GetParentSystemDir(dirOthier);

            // если диски различаются, выходим
            if (sysDir.FullPath != Gl.GetParentSystemDir(DirEdit).FullPath) return;

            // если стоит флаг "Обновлять если одинаковый системный каталог"
            if (RefillIfOneSyssDir)
            {
                if (lvEdit == lv1) { RefillList(2); }
                if (lvEdit == lv2) { RefillList(1); }
                return;
            }

            // смотрим есть ли еще каталог на диске
            // если нет, равняем каталоги
            if (DBItem.GetItemByPath(dirOthier.FullPath, Gl.DB) == null)
            {
                if (lvEdit == lv1) { Dir2 = Dir1; RefillList(2); }
                if (lvEdit == lv2) { Dir1 = Dir2; RefillList(1); }
            }

            Label lblPath = lvOther == lv1 ? lblPath1 : lblPath2;
            lblPath.Text = GetPath(dirOthier) + "\\*.*";

            // если каталог тот же, просто перезаполняем
            if (DirEdit.FullPath == dirOthier.FullPath)
            {
                if (lvEdit == lv1) { RefillList(2); }
                if (lvEdit == lv2) { RefillList(1); }
            }

        }

        #endregion *** Refill *******************************************************

        /// <summary> Отображаемый путь до каталога Dir </summary>
        string GetPath(DIR Dir)
        {
            DIR sysDir = Gl.GetParentSystemDir(Dir);
            int Len1 = sysDir.FPath.Length;
            int Len2 = Dir.FPath.Length;
            string s = Dir.FPath.Substring(Len1, Len2 - Len1);
            if (sysDir.FullPath == LocalDir.FullPath) return "L:" + s;
            if (sysDir.FullPath == NetDir.FullPath) return "N:" + s;
            if (sysDir.FullPath == RecyclerDir.FullPath) return "Корзина:" + s;

            return "";
        }

        /// <summary> Обновление иконок, если в окнах отображается содержимое сетевых папок </summary>
        void UpdateIcoIfNeed()
        {
            if (Gl.GetParentSystemDir(Dir1).FullPath == NetDir.FullPath) UpdateIco(lv1, Dir1.IsSystemDir);
            if (Gl.GetParentSystemDir(Dir2).FullPath == NetDir.FullPath) UpdateIco(lv2, Dir2.IsSystemDir);
        }

        void UpdateIco(ListView lv, bool IsSysDir)
        {
            for (int i = IsSysDir ? 0 : 1; i < lv.Items.Count; i++)
            {
                Element elm = (Element)lv.Items[i].Tag;
                int icoInd = Gl.GetIcoInd(elm);
                if (lv.Items[i].ImageIndex != icoInd) lv.Items[i].ImageIndex = icoInd;
            }
        }

        void UpdateIcoInDirIfNeed(Element Dir)
        {
            if (Dir.FullPath == Dir1.FullPath) UpdateIco(lv1, Dir1.IsSystemDir);
            if (Dir.FullPath == Dir2.FullPath) UpdateIco(lv2, Dir2.IsSystemDir);
        }

        /// <summary> выделение всех элементов листа </summary>
        void SelectAll(int ListInd)
        {
            ListView lv = ListInd == 1 ? lv1 : lv2;
            DIR Dir = ListInd == 1 ? Dir1 : Dir2;

            lv.SelectedIndices.Clear();
            for (int i = Dir.IsSystemDir ? 0 : 1; i < lv.Items.Count; i++) lv.SelectedIndices.Add(i);
        }

        void StepUp(int ListInd)
        {
            ListView lv = ListInd == 1 ? lv1 : lv2;
            if (ListInd == 1) Dir1 = (DIR)Dir1.Parent;
            else Dir2 = (DIR)Dir2.Parent;
            RefillList(ListInd);
            //lv.SelectedIndices.Add(0);
        }

        void DeleteItems(int ListInd)
        {
            ListView lv = lv1;
            DIR Dir = Dir1;
            if (ListInd == 2)
            {
                lv = lv2;
                Dir = Dir2;
            }

            //if (lv1.SelectedIndices.Count == 0) return;
            if (MessageBox.Show("Действительно удалить выделенные элементы?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                for (int i = 0; i < lv.SelectedIndices.Count; i++)
                {
                    if (!Dir.IsSystemDir && lv.SelectedIndices[i] == 0)
                    {
                        lv.SelectedIndices.Remove(i);
                        i--;
                        continue;
                    }
                    Element elm = (Element)lv.SelectedItems[i].Tag;
                    Gl.DeleteItem(elm);
                    Gl.AddToRecycler(elm);
                    tBtnRecycler1.Image = Properties.Resources.recycle_full;
                }
                btnClearRecycler.Enabled = RecyclerDir.Items.Count > 0;
                RefillList(lv, Dir);
                if (Dir1.FullPath == RecyclerDir.FullPath) RefillList(1);
                RefillOtherListIfNeed(lv, Dir);
                Gl.SaveDB();
            }
        }

        void SetAllDateNextGetVertion(DateTime dtForSet)
        {
            dtNextGetVertion = dtForSet;
            for (int i = 0; i < Gl.exl.Count; i++) Gl.exl[i].dtNextGetVertion = dtForSet;//.AddSeconds(i * 3 + 3);
        }

        #endregion *** Прочие Фии *********************************************************************************

        #region *** События листов ***************************************************************************

        private void lv_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ListView lv = (ListView)sender;
            int listInd = lv == lv1 ? 1 : 2;
            DIR Dir = listInd == 1 ? Dir1 : Dir2;

            if (lv.SelectedIndices.Count == 0) return;

            // если наверх
            if (!Dir.IsSystemDir && lv.SelectedIndices[0] == 0)
            {
                StepUp(listInd);
                return;
            }

            Element el = (Element)lv.SelectedItems[0].Tag;

            // если это каталог для других элементов
            if (el.Ext == "")
            {
                if (listInd == 1) Dir1 = (DIR)el;
                else Dir2 = (DIR)el;
                RefillList(listInd);
                //lv.SelectedIndices.Add(0);
            }
            // если это элемент
            else
            {
                // редактирование
                if (((VisibleUnit)el.Glob).Edit(el)) Gl.SaveDB();
            }
        }

        private void lv_KeyDown(object sender, KeyEventArgs e)
        {
            ListView lv = ((ListView)sender);
            int ListInd = Convert.ToInt32(lv.Tag);
            DIR Dir = ListInd == 1 ? Dir1 : Dir2;

            //Выделение по ctrl+A
            if (e.Control && e.KeyCode == Keys.A) SelectAll(ListInd);
            //Удаление по Delete
            if (e.KeyCode == Keys.Delete) DeleteItems(ListInd);
            //Выход из каталога по BackSpace 
            if (e.KeyCode == Keys.Back && !Dir.IsSystemDir) StepUp(ListInd);
            //Открытие по Enter
            if (e.KeyCode == Keys.Enter && (Dir.IsSystemDir || lv.SelectedIndices.Count > 0)) lv_MouseDoubleClick(sender, null);
            // снятие выделения по Esc
            if (e.KeyCode == Keys.Escape) ((ListView)sender).SelectedIndices.Clear();
        }

        private void lv_BeforeLabelEdit(object sender, LabelEditEventArgs e)
        {
            ListView lv = (ListView)sender;
            Element el = (Element)lv.SelectedItems[0].Tag;

            if (el.Ext == "" && ((DIR)el).IsSystemDir) e.CancelEdit = true;
            else el.IsEdit = true;
        }

        private void lv_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            ListView lv = (ListView)sender;
            Element el = (Element)lv.Items[e.Item].Tag;
            el.IsEdit = false;

            if (e.Label == null) return; // если отмена редактирования

            DIR Dir = lv == lv1 ? Dir1 : Dir2;
            string nm = e.Label.Trim();
            string err = Gl.CheckName(Dir, el, nm);
            if (err != "")
            {
                MessageBox.Show(err);
                e.CancelEdit = true;
                return;
            }

            if (el.NetStat != NetStatus.Local)
            {
                // если отредактировано имя каталога
                // значит все дочерние элементы поменяли свои полные имена. Поскольку привязка именно по ним, удаляем их
                Gl.AddElInDeleteNetList(el);
            }

            // меняем имя элемента
            el.Name = nm;

            if (el.NetStat != NetStatus.Local)
            {
                // если отредактировано имя каталога
                // значит все дочерние элементы поменяли свои полные имена. Поскольку привязка именно по ним, снова добавляем их
                if (el.Ext == "")
                {
                    List<DBItem> chEl = Gl.GetAllItems((DIR)el);
                    for (int i = 0; i < chEl.Count; i++) ((Element)chEl[i]).IsNew = true; // говорим, что все дочерние элементы теперь новые
                }
                el.NetStat = NetStatus.NotActual;
                UpdateIcoIfNeed();
            }

            RefillOtherListIfNeed(lv, Dir);
            Gl.SaveDB();
        }

        private void lv_SelectedIndexChanged(object sender, EventArgs e)
        {
            /*ListView lv = (ListView)sender;
            DIR Dir = lv == lv1 ? Dir1 : Dir2;
            if (!Dir.IsSystemDir && lv.SelectedIndices.IndexOf(0)!=-1)
            {
                lv.SelectedIndices.Remove(0);
            }*/
        }

        private void lv_ClientSizeChanged(object sender, EventArgs e)
        {
            //ListView lv = (ListView)sender;
            //lv.TileSize = new Size(lv.ClientSize.Width-20, lv.TileSize.Height);
        }

        private void lv_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            if (bWriteLocation) return;

            Gl.sett.ClmWidth1_Name = clmName1.Width;
            Gl.sett.ClmWidth2_Name = clmName2.Width;
            Gl.sett.ClmWidth1_Comm = clmComm1.Width;
            Gl.sett.ClmWidth2_Comm = clmComm2.Width;
            Gl.sett.Save();
        }

        #endregion *** События листов ***************************************************************************

        #region *** События меню ************************************************************************

        private void mBtnAdd_Click(object sender, EventArgs e)
        {
            DIR Dir = Dir1;
            ToolStripMenuItem mBtn = (ToolStripMenuItem)sender;
            int listNum = (int)mBtn.Tag;
            if (listNum == 2) Dir = Dir2;

            string ext = mBtn.Name;
            ext = ext.Substring(9, ext.Length - 9);
            Element el = ((VisibleUnit)Gl.unL[ext]).CreateNew(Dir, Dir.NetStat == NetStatus.Local ? NetStatus.Local : NetStatus.NotActual);
            if (el != null)
            {
                Dir.Items.Add(el);
                Dir.Items.Sort();
                RefillList(listNum);
                RefillOtherListIfNeed(listNum);
                Gl.SaveDB();
            }
        }

        private void mBtnDel_Click(object sender, EventArgs e)
        {
            DeleteItems((int)((ToolStripMenuItem)sender).Tag);
        }

        private void menu_Opening(object sender, CancelEventArgs e)
        {
            ContextMenuStrip menu = (ContextMenuStrip)sender;
            ListView lv = menu == menu1 ? lv1 : lv2;
            DIR Dir = menu == menu1 ? Dir1 : Dir2;

            if (sender == menu1 && Gl.GetParentSystemDir(Dir1).FullPath == RecyclerDir.FullPath) { e.Cancel = true; return; };

            if (!Dir.IsSystemDir && lv.SelectedIndices.Count > 0 && lv.SelectedIndices[0] == 0)
            {
                lv.SelectedIndices.Remove(0);
                if (lv.SelectedIndices.Count == 0) { e.Cancel = true; return; }
            }

            Element el = null;
            if (lv.SelectedIndices.Count > 0) el = (Element)lv.SelectedItems[0].Tag;

            for (int i = 0; i < menu.Items.Count; i++)
            {
                if (menu.Items[i].GetType() == typeof(ToolStripMenuItem))
                {
                    ToolStripMenuItem tBtn = (ToolStripMenuItem)menu.Items[i];
                    if (tBtn.Name == "mBtnDel" + (sender == menu1 ? 1 : 2)) tBtn.Enabled = el != null;
                    else tBtn.Enabled = el == null;
                }
            }
        }

        #endregion *** События меню ************************************************************************

        #region *** кнопки разделов ***********************************************************************

        private void tBtnLocal1_Click(object sender, EventArgs e)
        {
            tBtnLocal1.Checked = true;
            tBtnNet1.Checked = false;
            tBtnRecycler1.Checked = false;
            btnClearRecycler.Visible = false;
            if (Dir1.FullPath != LocalDir.FullPath)
            {
                Dir1 = (DIR)DBItem.GetItemByPath(LastLocalDir, Gl.DB);
                if (Dir1 == null) Dir1 = LocalDir;

                RefillList(1);
            }
        }

        private void tBtnLocal2_Click(object sender, EventArgs e)
        {
            tBtnLocal2.Checked = true;
            tBtnNet2.Checked = false;
            if (Dir2.FullPath != LocalDir.FullPath)
            {
                Dir2 = (DIR)DBItem.GetItemByPath(LastLocalDir, Gl.DB);
                if (Dir2 == null) Dir2 = LocalDir;

                RefillList(2);
            }
        }

        private void tBtnNet1_Click(object sender, EventArgs e)
        {
            tBtnLocal1.Checked = false;
            tBtnNet1.Checked = true;
            tBtnRecycler1.Checked = false;
            btnClearRecycler.Visible = false;
            if (Dir1.FullPath != NetDir.FullPath)
            {
                Dir1 = (DIR)DBItem.GetItemByPath(LastNetDir, Gl.DB);
                if (Dir1 == null) Dir1 = NetDir;

                RefillList(1);
            }
        }

        private void tBtnNet2_Click(object sender, EventArgs e)
        {
            tBtnLocal2.Checked = false;
            tBtnNet2.Checked = true;
            if (Dir2.FullPath != NetDir.FullPath)
            {
                Dir2 = (DIR)DBItem.GetItemByPath(LastNetDir, Gl.DB);
                if (Dir2 == null) Dir2 = NetDir;

                RefillList(2);
            }
        }

        private void tBtnRecycler1_Click(object sender, EventArgs e)
        {
            tBtnLocal1.Checked = false;
            tBtnNet1.Checked = false;
            tBtnRecycler1.Checked = true;
            btnClearRecycler.Visible = true;
            if (Dir1.FullPath != RecyclerDir.FullPath)
            {
                Dir1 = RecyclerDir;
                RefillList(1);
            }
        }

        #endregion *** кнопки разделов ***********************************************************************

        #region *** Drag And Drop ******************************************************************

        private void lv_ItemDrag(object sender, ItemDragEventArgs e)
        {
            ListView lv = (ListView)sender;

            DIR Dir = lv == lv1 ? Dir1 : Dir2;
            if (!Dir.IsSystemDir && lv.SelectedIndices.IndexOf(0) != -1)
            {
                if (lv.SelectedIndices.Count == 1) return;
                else lv.SelectedIndices.Remove(0);
            }

            DragSrsView = lv;
            lv.DoDragDrop(lv.SelectedItems, DragDropEffects.Move);

        }

        private void lv_DragEnter(object sender, DragEventArgs e)
        {
            ListView lv = (ListView)sender;

            if (lv == lv1 && Gl.GetParentSystemDir(Dir1).FullPath == RecyclerDir.FullPath) return;

            int len = e.Data.GetFormats().Length - 1;
            int i;
            for (i = 0; i <= len; i++)
            {
                if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
                {
                    //The data from the drag source is moved to the target.	
                    e.Effect = DragDropEffects.Move;
                }
            }
        }

        ListViewItem DragOverItem = null;
        ListView DragSrsView = null;

        private void lv_DragDrop(object sender, DragEventArgs e)
        {
            ListView lvTo = (ListView)sender;
            ListView lvFrom = DragSrsView;
            DIR DirTo = lvTo == lv1 ? Dir1 : Dir2;
            DIR DirFrom = lvFrom == lv1 ? Dir1 : Dir2;

            if (lvFrom.SelectedItems.Count == 0) return;

            DIR destDir;
            if (DragOverItem == null) destDir = DirTo; //если пустое место
            else if (DragOverItem.Tag == null) destDir = (DIR)DirTo.Parent;   // если позиция верх
            else if (((Element)DragOverItem.Tag).Ext == "") destDir = (DIR)DragOverItem.Tag;   // если каталог
            else destDir = DirTo; // если элемент 

            DIR srsDir = DirFrom;

            if (srsDir.FullPath == destDir.FullPath)
            {
                MessageBox.Show("Нельзя перенести в тот же каталог");
                return;
            }

            // проверка на копирование в самого себя
            for (int i = 0; i < lvFrom.SelectedItems.Count; i++)
            {
                Element elm = (Element)lvFrom.SelectedItems[i].Tag;
                if (elm.FullPath == destDir.FullPath)
                {
                    MessageBox.Show("Нельзя скопировать элемент сам в себя");
                    return;
                }
            }

            string msg = "Перенести " + (lvFrom.SelectedItems.Count > 1 ? "выделенные элементы" : "выделенный элемент") + " в каталог '" + GetPath(destDir) + "\\' ?";
            if (MessageBox.Show(msg, "Перемещение", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                MoveItems(lvFrom, srsDir, destDir);
                RefillList(lvFrom, DirFrom);
                if (lvFrom != lvTo) RefillList(lvTo, DirTo);
                else
                {
                    RefillOtherListIfNeed(lvFrom, DirFrom, true);
                }

                // если перенесено из корзины
                if (srsDir.FullPath == RecyclerDir.FullPath)
                {
                    tBtnRecycler1.Image = RecyclerDir.Items.Count == 0 ? Properties.Resources.recycle_empty : Properties.Resources.recycle_full;
                    btnClearRecycler.Enabled = RecyclerDir.Items.Count > 0;
                }

                Gl.SaveDB();
            }

            DragOverItem = null;
            DragSrsView = null;

        }

        // возвращает true, если хотябы 1 элемент перенесен
        bool MoveItems(ListView srsLv, DIR srsDir, DIR destDir)
        {
            List<int> moveIndList = new List<int>();
            for (int i = 0; i < srsLv.SelectedItems.Count; i++)
                moveIndList.Add(srsDir.IndexOfRecord(((DBItem)srsLv.SelectedItems[i].Tag).NameExt));

            List<int> MovedIndL = srsDir.MoveItems(moveIndList, destDir, new DBItem.GetActionWithDuplDelegate(GetActionWithDupl), new DBItem.OnMoveDelegate(BeforeMoveItem), new DBItem.OnMoveDelegate(AfterMoveItem));

            return MovedIndL.Count > 0;
        }

        static DBItem.ActionWithDupl GetActionWithDupl(DBItem oldItem, DBItem newItem)
        {
            if (newItem.Ext == "") return DBItem.ActionWithDupl.AppendItems;

            Element oldEl = (Element)oldItem;
            Element newEl = (Element)newItem;
            string mess = "Элемент с именем '" + newEl.Name + "' уже существует. Заменить его новым?\r\n";
            mess += "СУЩЕСТВУЮЩИЙ ЭЛЕМЕНТ:\r\n\t" + oldEl.FPath + "\r\n";
            mess += "НОВЫЙ ЭЛЕМЕНТ:\r\n\t" + newEl.FPath;
            if (MessageBox.Show(mess, "Перемещение", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
                return DBItem.ActionWithDupl.NotReplase;

            return DBItem.ActionWithDupl.Replace;
        }

        public void BeforeMoveItem(DBItem moveItem, DBItem.MoveAction MoveActn)
        {
            // находим все перенесенные элементы, включая дочернии
            List<DBItem> el = new List<DBItem>();

            // если элемент - это каталог, берем все его дочерние элементы
            if (moveItem.Ext == "")
                el = Gl.GetAllItems((DIR)moveItem);
            el.Insert(0, moveItem);

            for (int i = 0; i < el.Count; i++)
            {
                Element elm = (Element)el[i];
                DIR sysDir = Gl.GetParentSystemDir(elm);
                // если элемент сетевой, добавляем его в список удаления
                if (sysDir.FullPath == NetDir.FullPath) Gl.DelList.Add(elm.FullPath);
            }
        }

        public void AfterMoveItem(DBItem moveItem, DBItem.MoveAction MoveActn)
        {
            // находим все перенесенные элементы, включая дочернии
            List<DBItem> el = new List<DBItem>();

            // если элемент - это каталог и он добавлялся, а не просто дополнялся, берем все его дочерние элементы
            if (MoveActn != DBItem.MoveAction.AppendItems && moveItem.Ext == "")
                el = Gl.GetAllItems((DIR)moveItem);

            el.Insert(0, moveItem);

            for (int i = 0; i < el.Count; i++)
            {
                Element elm = (Element)el[i];
                DIR sysDir = Gl.GetParentSystemDir(elm);

                if (sysDir.FullPath == NetDir.FullPath)
                {
                    // если элемент не просто дополнялся, считаем элемент вновь добавленым
                    if (MoveActn != DBItem.MoveAction.AppendItems)
                    {
                        elm.IsNew = true;
                        elm.NetStat = NetStatus.NotActual;
                    }
                }
                else
                    elm.NetStat = NetStatus.Local;
            }
        }

        private void lv_DragOver(object sender, DragEventArgs e)
        {
            ListView lv = (ListView)sender;

            Point cp = lv.PointToClient(new Point(e.X, e.Y));
            //ListViewItem LastDragOverItem = DragOverItem;
            DragOverItem = lv.GetItemAt(cp.X, cp.Y);

            if (DragOverItem != null)
            {
                ; //if (DragOverItem.ImageIndex != 1) DragOverItem.ImageIndex = 1;
            }
            //if (LastDragOverItem != null && (DragOverItem == null || DragOverItem.Index != LastDragOverItem.Index)) LastDragOverItem.ImageIndex = 0;*/

        }

        #endregion *** Drag And Drop ***************************************************************

        #region *** для дебага **************************************************************************

        private void button1_Click(object sender, EventArgs e)
        {
            Gl.AddDebugLogTitle("ЗАПРОС НА СИНХРОНИЗАЦИЮ");

            /*// делаем все неактуальным (для теста)
            List<DBItem> el = Gl.GetAllItems(NetDir);
            for (int i = 0; i < el.Count; i++) ((Element)el[i]).NetStat = NetStatus.NotActual;*/

            //Gl.ServVertion = DateTime.MinValue; // сбрасываем версию (для теста)

            frmServ.RequestSinc(NetDir, false);
            UpdateIcoIfNeed();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Gl.ServVertion = 0; // сбрасываем версию (для теста)

            frmServ.RequestSinc(NetDir, false);
            UpdateIcoIfNeed();
        }

        #endregion *** для дебага **************************************************************************

        private void btnClearRecycler_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Очистить корзину?", "Очистка корзины", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                for (int i = 0; i < RecyclerDir.Items.Count; i++) ((Element)RecyclerDir.Items[i]).Dispose();
                RecyclerDir.Items.Clear();
                tBtnRecycler1.Image = Properties.Resources.recycle_empty;
                btnClearRecycler.Enabled = false;
                RefillList(1);
                Gl.SaveDB();
            }
        }

        #region *** Трей (меню и события трея) ************************************************************************

        bool bClose = false;
        private void mBtnClose_Click(object sender, EventArgs e)
        {
            bClose = true;
            Close();
        }

        bool bWriteLocation = false;
        private void notifyMain_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (!Visible)
            {
                bWriteLocation = true;

                Show();
                WindowState = FormWindowState.Normal;

                #region *** начальное положение ***********************
                Rectangle disp = Screen.PrimaryScreen.WorkingArea;
                bool bReSave = false;
                Location = Gl.sett.Frm_Location;
                Size = Gl.sett.Frm_Size;
                if (Location.X < disp.X || Location.Y < disp.Y) { Location = new Point(disp.X, disp.Y); Gl.sett.Frm_Location = Location; bReSave = true; }
                if ((Location.X + MinimumSize.Width) > disp.Right || (Location.Y + MinimumSize.Height) > disp.Bottom) { Location = new Point(disp.Right - MinimumSize.Width, disp.Bottom - MinimumSize.Height); Gl.sett.Frm_Location = Location; bReSave = true; }

                // ширины столбцов
                /*clmName1.Width = Gl.sett.ClmWidth1_Name;
                clmName2.Width = Gl.sett.ClmWidth2_Name;
                clmComm1.Width = Gl.sett.ClmWidth1_Comm;
                clmComm2.Width = Gl.sett.ClmWidth2_Comm;*/

                if (bReSave) Gl.sett.Save();

                #endregion *** начальное положение ***********************

                bWriteLocation = false;
            }

            Activate();
        }

        private void mBtnEditService_Click(object sender, EventArgs e)
        {
            string oldLogin = Gl.sett.Login;

            frmServ.ShowDialog();

            if (oldLogin != Gl.sett.Login)
            {
                LoadUserLocalData();
            }

            SetAllDateNextGetVertion(DateTime.Now);
            dtReconnet = DateTime.Now;
        }

        private void mBtnGuests_Click(object sender, EventArgs e)
        {
            if (!mBtnGuests.Checked)
            {
                mBtnGuests.Enabled = false;
                FormEdit frmEdit = new FormEdit();
                frmEdit.StartPosition = FormStartPosition.Manual;
                Point crs = Cursor.Position;
                frmEdit.Location = new Point(crs.X - frmEdit.Width / 2, crs.Y - frmEdit.Height / 2);
                frmEdit.TopMost = true;
                bool bReturn = false;
                if (!frmEdit.ShowDialog("Пароль", "", ClosefrmEditPass))
                {
                    mBtnGuests.Checked = true;
                    bReturn = true;
                }
                frmEdit.Dispose();
                frmEdit = null;
                mBtnGuests.Enabled = true;
                if (bReturn) return;
            }
            Gl.sett.Guests = mBtnGuests.Checked;

            foreach (KeyValuePair<string, IElementUnit> u in Gl.unL) u.Value.GuestModeChange(mBtnGuests.Checked);
            foreach (ExtElementUnit ext in Gl.exl) ext.ExElm.GuestModeChange(mBtnGuests.Checked);
            foreach (ExternalExe exExe in Gl.exExeL) exExe.GuestModeChange(mBtnGuests.Checked);

            Gl.sett.Save();
        }

        bool ClosefrmEditPass(object sender, string RetVal)
        {
            if (RetVal.Trim().ToLower() == "qwepoiqwe") return true;
            MessageBox.Show("Пароль неверный");
            return false;
        }

        private void mBtnEditSett_Click(object sender, EventArgs e)
        {
            FormSettings frmSett = new FormSettings();
            frmSett.ShowDialog();
            frmSett.Dispose();
        }

        private void menuTray_Opening(object sender, CancelEventArgs e)
        {
            for (int i = 0; i < menuTray.Items.Count; i++)
            {
                if (menuTray.Items[i].Name != "mBtnGuests" && menuTray.Items[i].Name != "mBtnClose") menuTray.Items[i].Enabled = !Gl.sett.Guests;
            }
        }

        #endregion *** Трей (меню и события трея) ************************************************************************




    }
}
